<!--2025-6-4 陈祯宇 创作-->
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数据可视化工具 | 学生练习平台</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>

    <!-- Tailwind 配置 -->
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#6366F1', // 主色调：紫色
                        secondary: '#F97316', // 辅助色：橙色
                        accent: '#EC4899', // 强调色：粉色
                        neutral: {
                            100: '#F3F4F6',
                            200: '#E5E7EB',
                            300: '#D1D5DB',
                            400: '#9CA3AF',
                            500: '#6B7280',
                            600: '#4B5563',
                            700: '#374151',
                            800: '#1F2937',
                            900: '#111827'
                        }
                    },
                    fontFamily: {
                        inter: ['Inter', 'system-ui', 'sans-serif'],
                    },
                    boxShadow: {
                        'card': '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
                        'card-hover': '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
                    }
                }
            }
        }
    </script>

    <!-- 自定义工具类 -->
    <style type="text/tailwindcss">
        @layer utilities {
            .content-auto {
                content-visibility: auto;
            }
            .card-transition {
                transition: all 0.3s ease;
            }
            .btn-hover {
                transition: all 0.2s ease;
            }
            .btn-hover:hover {
                transform: translateY(-2px);
            }
            .chart-container {
                position: relative;
                height: 400px;
                width: 100%;
            }
        }
    </style>
</head>

<body class="font-inter bg-gradient-to-br from-neutral-100 to-neutral-200 min-h-screen">
    <!-- 顶部导航 -->
    <header class="bg-white shadow-lg rounded-b-2xl mx-4 md:mx-8 mt-4 overflow-hidden">
        <div class="container mx-auto px-4 py-6">
            <h1 class="text-[clamp(1.8rem,5vw,3rem)] font-extrabold text-center text-primary">
                数据可视化工具 📊
            </h1>
            <p class="text-center text-neutral-600 mt-2 text-lg">
                记录并展示你的数据，选择不同的图表来展示数据吧！
            </p>
        </div>
    </header>

    <main class="container mx-auto px-4 py-8">
        <!-- 数据输入和图表区域 -->
        <div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
            <!-- 左侧数据输入区域 -->
            <div class="lg:col-span-1 space-y-6">
                <!-- 添加数据卡片 -->
                <div class="bg-white rounded-2xl shadow-card p-6 card-transition hover:shadow-card-hover">
                    <h2 class="text-2xl font-bold text-secondary mb-4 flex items-center">
                        <i class="fa fa-plus-circle mr-2"></i> 添加你的数据
                    </h2>

                    <form id="addDataForm" class="space-y-4">
                        <div>
                            <label for="hobby" class="block text-neutral-700 font-semibold mb-2">兴趣爱好名称</label>
                            <input type="text" id="hobby" placeholder="例如: 篮球、绘画"
                                class="w-full px-4 py-3 rounded-lg border-2 border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all"
                                required>
                        </div>

                        <div>
                            <label for="count" class="block text-neutral-700 font-semibold mb-2">人数统计</label>
                            <input type="number" id="count" placeholder="例如: 15"
                                class="w-full px-4 py-3 rounded-lg border-2 border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all"
                                min="1" required>
                        </div>

                        <div>
                            <label for="class" class="block text-neutral-700 font-semibold mb-2">选择班级</label>
                            <select id="class"
                                class="w-full px-4 py-3 rounded-lg border-2 border-neutral-200 focus:border-primary focus:ring-2 focus:ring-primary/20 outline-none transition-all">
                                <option value="一年级1班">一年级1班</option>
                                <option value="一年级2班">一年级2班</option>
                                <option value="一年级3班">一年级3班</option>
                                <option value="二年级1班">二年级1班</option>
                                <option value="二年级2班">二年级2班</option>
                                <option value="三年级1班">三年级1班</option>
                                <option value="三年级2班">三年级2班</option>
                                <option value="四年级1班">四年级1班</option>
                                <option value="四年级2班">四年级2班</option>
                                <option value="五年级1班">五年级1班</option>
                                <option value="五年级2班">五年级2班</option>
                                <option value="六年级1班">六年级1班</option>
                                <option value="六年级2班">六年级2班</option>
                            </select>
                        </div>

                        <div>
                            <label class="block text-neutral-700 font-semibold mb-2">选择颜色</label>
                            <div class="flex flex-wrap items-center gap-3">
                                <div class="grid grid-cols-5 gap-2 flex-1">
                                    <input type="radio" name="color" value="#6366F1" id="color1" class="hidden peer"
                                        checked>
                                    <label for="color1"
                                        class="w-full h-10 rounded-full bg-[#6366F1] cursor-pointer border-2 border-transparent peer-checked:border-white peer-checked:ring-2 peer-checked:ring-[#6366F1] transition-all"></label>

                                    <input type="radio" name="color" value="#F97316" id="color2" class="hidden peer">
                                    <label for="color2"
                                        class="w-full h-10 rounded-full bg-[#F97316] cursor-pointer border-2 border-transparent peer-checked:border-white peer-checked:ring-2 peer-checked:ring-[#F97316] transition-all"></label>

                                    <input type="radio" name="color" value="#EC4899" id="color3" class="hidden peer">
                                    <label for="color3"
                                        class="w-full h-10 rounded-full bg-[#EC4899] cursor-pointer border-2 border-transparent peer-checked:border-white peer-checked:ring-2 peer-checked:ring-[#EC4899] transition-all"></label>

                                    <input type="radio" name="color" value="#10B981" id="color4" class="hidden peer">
                                    <label for="color4"
                                        class="w-full h-10 rounded-full bg-[#10B981] cursor-pointer border-2 border-transparent peer-checked:border-white peer-checked:ring-2 peer-checked:ring-[#10B981] transition-all"></label>

                                    <input type="radio" name="color" value="#3B82F6" id="color5" class="hidden peer">
                                    <label for="color5"
                                        class="w-full h-10 rounded-full bg-[#3B82F6] cursor-pointer border-2 border-transparent peer-checked:border-white peer-checked:ring-2 peer-checked:ring-[#3B82F6] transition-all"></label>
                                </div>

                                <div class="relative">
                                    <input type="color" id="customColor" value="#6366F1"
                                        class="absolute w-10 h-10 opacity-0 cursor-pointer">
                                    <div class="w-10 h-10 rounded-full bg-[#6366F1] border-2 border-white shadow-md cursor-pointer flex items-center justify-center"
                                        id="customColorPreview">
                                        <i class="fa fa-paint-brush text-white"></i>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <button type="submit"
                            class="w-full bg-primary hover:bg-primary/90 text-white font-bold py-3 px-6 rounded-lg shadow-lg transition-all btn-hover">
                            <i class="fa fa-plus mr-2"></i> 添加数据
                        </button>
                    </form>
                </div>

                <!-- 数据列表卡片 -->
                <div class="bg-white rounded-2xl shadow-card p-6 card-transition hover:shadow-card-hover">
                    <h2 class="text-2xl font-bold text-accent mb-4 flex items-center">
                        <i class="fa fa-list-alt mr-2"></i> 数据列表
                    </h2>

                    <div id="dataList" class="space-y-3 max-h-[300px] overflow-y-auto pr-2">
                        <div class="text-neutral-500 italic text-center py-4">
                            暂无数据，请添加兴趣爱好数据
                        </div>
                    </div>

                    <div class="grid grid-cols-2 gap-3 mt-4">
                        <button id="clearDataBtn"
                            class="bg-neutral-200 hover:bg-neutral-300 text-neutral-700 font-semibold py-2 rounded-lg transition-all btn-hover">
                            <i class="fa fa-trash mr-1"></i> 清空数据
                        </button>
                        <button id="shuffleDataBtn"
                            class="bg-secondary hover:bg-secondary/90 text-white font-semibold py-2 rounded-lg transition-all btn-hover">
                            <i class="fa fa-random mr-1"></i> 乱序数据
                        </button>
                    </div>

                    <button id="exportCSVBtn"
                        class="w-full mt-3 bg-primary hover:bg-primary/90 text-white font-bold py-2 rounded-lg transition-all btn-hover">
                        <i class="fa fa-download mr-1"></i> 导出为 CSV
                    </button>
                </div>
            </div>

            <!-- 右侧图表区域 -->
            <div class="lg:col-span-2 space-y-6">
                <!-- 图表类型选择卡片 -->
                <div class="bg-white rounded-2xl shadow-card p-6 card-transition hover:shadow-card-hover">
                    <h2 class="text-2xl font-bold text-primary mb-4 flex items-center">
                        <i class="fa fa-chart-pie mr-2"></i> 选择图表类型
                    </h2>

                    <div class="grid grid-cols-2 md:grid-cols-5 gap-3" id="chartTypeContainer">
                        <!-- 图表类型按钮将通过 JavaScript 动态添加 -->
                    </div>
                </div>

                <!-- 图表展示卡片 -->
                <div class="bg-white rounded-2xl shadow-card p-6 card-transition hover:shadow-card-hover">
                    <h2 class="text-2xl font-bold text-secondary mb-4 flex items-center">
                        <i class="fa fa-bar-chart mr-2"></i> 数据可视化
                    </h2>

                    <div class="chart-container">
                        <canvas id="myChart"></canvas>
                    </div>

                    <div id="emptyChartMessage" class="text-center text-neutral-500 italic py-8">
                        请添加数据以生成图表
                    </div>
                </div>
            </div>
        </div>
    </main>

    <!-- 通知提示 -->
    <div id="notification"
        class="fixed top-4 right-4 bg-white shadow-lg rounded-lg p-4 transform translate-x-full transition-transform duration-300 z-50 max-w-xs">
        <div class="flex items-start">
            <div id="notificationIcon" class="text-green-500 mr-3 text-xl"></div>
            <div>
                <h3 id="notificationTitle" class="font-bold text-neutral-800"></h3>
                <p id="notificationMessage" class="text-neutral-600 text-sm"></p>
            </div>
            <button id="closeNotification" class="ml-auto text-neutral-400 hover:text-neutral-600">
                <i class="fa fa-times"></i>
            </button>
        </div>
    </div>

    <script>
        // 数据数组
        let hobbyData = [];

        // 当前活动图表类型
        let activeChartType = 'bar';

        // 图表类型配置
        const chartTypes = [
            { type: 'bar', name: '柱状图', icon: 'fa-bar-chart' },
            { type: 'pie', name: '饼图', icon: 'fa-pie-chart' },
            { type: 'line', name: '折线图', icon: 'fa-line-chart' },
            { type: 'doughnut', name: '环形图', icon: 'fa-circle-o' },
            { type: 'polarArea', name: '极区图', icon: 'fa-dot-circle-o' }
        ];

        // DOM 元素
        const addDataForm = document.getElementById('addDataForm');
        const exportCSVBtn = document.getElementById('exportCSVBtn');
        const clearDataBtn = document.getElementById('clearDataBtn');
        const shuffleDataBtn = document.getElementById('shuffleDataBtn');
        const dataList = document.getElementById('dataList');
        const notification = document.getElementById('notification');
        const notificationIcon = document.getElementById('notificationIcon');
        const notificationTitle = document.getElementById('notificationTitle');
        const notificationMessage = document.getElementById('notificationMessage');
        const closeNotification = document.getElementById('closeNotification');
        const chartTypeContainer = document.getElementById('chartTypeContainer');
        const emptyChartMessage = document.getElementById('emptyChartMessage');
        const ctx = document.getElementById('myChart').getContext('2d');
        const customColor = document.getElementById('customColor');
        const customColorPreview = document.getElementById('customColorPreview');
        let chart = null;

        // 自定义颜色处理
        customColor.addEventListener('input', function () {
            // 更新预览颜色
            customColorPreview.style.backgroundColor = this.value;

            // 取消其他颜色选择
            document.querySelectorAll('input[name="color"]').forEach(radio => {
                radio.checked = false;
            });

            // 创建一个隐藏的radio来存储自定义颜色
            let customRadio = document.getElementById('customColorRadio');
            if (!customRadio) {
                customRadio = document.createElement('input');
                customRadio.type = 'radio';
                customRadio.name = 'color';
                customRadio.id = 'customColorRadio';
                customRadio.classList.add('hidden');
                document.body.appendChild(customRadio);
            }

            customRadio.value = this.value;
            customRadio.checked = true;
        });

        // 初始化图表类型按钮
        function initChartTypeButtons() {
            chartTypeContainer.innerHTML = '';

            chartTypes.forEach((chartType, index) => {
                const btn = document.createElement('button');
                btn.className = `flex flex-col items-center justify-center p-3 rounded-xl border-2 transition-all ${index === 0 ? 'border-primary bg-primary/10 text-primary' : 'border-neutral-200 hover:border-primary hover:bg-primary/5 text-neutral-600'}`;
                btn.setAttribute('data-type', chartType.type);
                btn.innerHTML = `
                    <i class="fa ${chartType.icon} text-xl mb-1"></i>
                    <span class="text-sm">${chartType.name}</span>
                `;

                chartTypeContainer.appendChild(btn);
            });

            // 添加图表类型按钮点击事件
            document.querySelectorAll('#chartTypeContainer button').forEach(btn => {
                btn.addEventListener('click', function () {
                    // 更新按钮状态
                    document.querySelectorAll('#chartTypeContainer button').forEach(b => {
                        b.classList.remove('border-primary', 'bg-primary/10', 'text-primary');
                        b.classList.add('border-neutral-200', 'hover:border-primary', 'hover:bg-primary/5', 'text-neutral-600');
                    });

                    this.classList.add('border-primary', 'bg-primary/10', 'text-primary');
                    this.classList.remove('border-neutral-200', 'hover:border-primary', 'hover:bg-primary/5', 'text-neutral-600');

                    // 更新当前活动图表类型
                    activeChartType = this.getAttribute('data-type');

                    // 更新图表
                    updateChart();
                });
            });
        }

        // 更新数据列表
        function updateDataList() {
            if (hobbyData.length === 0) {
                dataList.innerHTML = `
                    <div class="text-neutral-500 italic text-center py-4">
                        暂无数据，请添加兴趣爱好数据
                    </div>
                `;
                return;
            }

            dataList.innerHTML = '';

            hobbyData.forEach((item, index) => {
                const itemDiv = document.createElement('div');
                itemDiv.className = 'bg-neutral-50 rounded-xl p-3 flex items-center justify-between group';
                itemDiv.innerHTML = `
                    <div class="flex items-center">
                        <div class="w-4 h-4 rounded-full mr-3" style="background-color: ${item.color}"></div>
                        <div>
                            <div class="font-semibold text-neutral-800">${item.hobby}</div>
                            <div class="text-sm text-neutral-600">${item.class} - ${item.count}人</div>
                        </div>
                    </div>
                    <div class="opacity-0 group-hover:opacity-100 transition-opacity">
                        <button class="text-red-500 hover:text-red-700 p-1" data-index="${index}" data-action="delete">
                            <i class="fa fa-trash"></i>
                        </button>
                    </div>
                `;

                dataList.appendChild(itemDiv);
            });

            // 添加删除事件监听
            document.querySelectorAll('[data-action="delete"]').forEach(btn => {
                btn.addEventListener('click', function () {
                    const index = parseInt(this.getAttribute('data-index'));
                    hobbyData.splice(index, 1);
                    updateDataList();
                    updateChart();
                });
            });
        }

        // 更新图表
        function updateChart() {
            if (hobbyData.length === 0) {
                if (chart) {
                    chart.destroy();
                    chart = null;
                }
                emptyChartMessage.style.display = 'block';
                return;
            }

            emptyChartMessage.style.display = 'none';

            const labels = hobbyData.map(item => `${item.hobby} (${item.class})`);
            const data = hobbyData.map(item => item.count);
            const backgroundColor = hobbyData.map(item => item.color);
            const borderColor = hobbyData.map(item => addOpacity(item.color, 1));

            if (chart) {
                chart.destroy();
            }

            // 根据不同图表类型设置不同配置
            let options = {
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    legend: {
                        position: 'right',
                        labels: {
                            font: {
                                family: 'Inter'
                            }
                        }
                    },
                    tooltip: {
                        callbacks: {
                            label: function (context) {
                                return `${context.label}: ${context.raw}人`;
                            }
                        }
                    }
                }
            };

            // 针对不同图表类型的特殊配置
            if (activeChartType === 'pie' || activeChartType === 'doughnut') {
                options.plugins.tooltip.callbacks.label = function (context) {
                    const label = context.label || '';
                    const value = context.raw || 0;
                    const total = context.dataset.data.reduce((acc, val) => acc + val, 0);
                    const percentage = Math.round((value / total) * 100);
                    return `${label}: ${value}人 (${percentage}%)`;
                };
            } else if (activeChartType === 'bar') {
                options.scales = {
                    y: {
                        beginAtZero: true,
                        grid: {
                            color: 'rgba(0, 0, 0, 0.05)'
                        }
                    },
                    x: {
                        grid: {
                            display: false
                        }
                    }
                };
            }

            chart = new Chart(ctx, {
                type: activeChartType,
                data: {
                    labels: labels,
                    datasets: [{
                        label: '人数统计',
                        data: data,
                        backgroundColor: backgroundColor,
                        borderColor: borderColor,
                        borderWidth: 1
                    }]
                },
                options: options
            });
        }

        // 添加数据表单提交事件
        addDataForm.addEventListener('submit', function (e) {
            e.preventDefault();

            const hobby = document.getElementById('hobby').value.trim();
            const count = parseInt(document.getElementById('count').value);
            const classValue = document.getElementById('class').value;

            // 获取选中的颜色
            let color;
            const selectedRadio = document.querySelector('input[name="color"]:checked');
            if (selectedRadio) {
                color = selectedRadio.value;
            } else {
                // 默认颜色
                color = '#6366F1';
            }

            // 验证输入
            if (!hobby) {
                showNotification('输入错误', '兴趣爱好名称不能为空', 'warning');
                return;
            }

            if (isNaN(count) || count <= 0) {
                showNotification('输入错误', '人数统计必须是大于0的数字', 'warning');
                return;
            }

            // 检查是否已存在相同的兴趣爱好和班级组合
            const existingIndex = hobbyData.findIndex(item =>
                item.hobby.toLowerCase() === hobby.toLowerCase() &&
                item.class === classValue
            );

            if (existingIndex !== -1) {
                // 如果已存在，更新数量和颜色
                hobbyData[existingIndex].count = count;
                hobbyData[existingIndex].color = color;
                showNotification('更新成功', `${hobby} (${classValue}) 的数据已更新`, 'info');
            } else {
                // 如果不存在，添加新数据
                hobbyData.push({ hobby, count, class: classValue, color });
                showNotification('添加成功', `${hobby} (${classValue}) 已添加到列表中`, 'success');
            }

            // 更新数据列表和图表
            updateDataList();
            updateChart();

            // 重置表单
            this.reset();
            document.querySelector('input[name="color"][value="#6366F1"]').checked = true;
            customColor.value = '#6366F1';
            customColorPreview.style.backgroundColor = '#6366F1';
        });

        // 清空数据按钮点击事件
        clearDataBtn.addEventListener('click', function () {
            if (hobbyData.length > 0) {
                if (confirm('确定要清空所有数据吗？')) {
                    hobbyData = [];
                    updateDataList();
                    updateChart();
                    showNotification('已清空数据', '所有兴趣爱好数据已被清除', 'info');
                }
            } else {
                showNotification('没有数据可清空', '数据列表已经是空的了', 'warning');
            }
        });

        // 乱序数据按钮点击事件
        shuffleDataBtn.addEventListener('click', function () {
            if (hobbyData.length === 0) {
                showNotification('操作失败', '请先添加数据', 'warning');
                return;
            }

            // 提取所有属性到数组
            const allHobbies = hobbyData.map(item => item.hobby);
            const allCounts = hobbyData.map(item => item.count);
            const allClasses = hobbyData.map(item => item.class);

            // 分别打乱每个属性数组
            shuffleArray(allHobbies);
            shuffleArray(allCounts);
            shuffleArray(allClasses);

            // 重新组合数据
            hobbyData.forEach((item, index) => {
                //随机数

                let a = Math.floor(Math.random() * 3) + 1;
                console.log("11111", a)
                if (a == 1) {
                    item.hobby = allCounts[index];
                    item.count = allHobbies[index];
                    item.class = allClasses[index];
                }
                if (a == 2) {
                    item.hobby = allClasses[index];
                    item.count = allHobbies[index];
                    item.class = allCounts[index];
                }
                if (a == 3) {
                    item.hobby = allHobbies[index];
                    item.count = allClasses[index];
                    item.class = allCounts[index];
                }

            });

            // 更新视图
            updateDataList();
            updateChart();

            showNotification('数据已乱序', '兴趣爱好名称、班级和人数统计已被随机交换', 'info');
        });

        // 导出为 CSV 按钮点击事件
        exportCSVBtn.addEventListener('click', function () {
            if (hobbyData.length === 0) {
                showNotification('导出失败', '没有数据可导出', 'warning');
                return;
            }

            // 构建CSV内容
            let csvContent = "兴趣爱好名称,班级,人数统计\n";
            hobbyData.forEach(item => {
                csvContent += `${item.hobby},${item.class},${item.count}\n`;
            });

            // 创建下载链接
            const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '兴趣爱好数据.csv';
            a.click();
            URL.revokeObjectURL(url);

            showNotification('导出成功', 'CSV文件已下载', 'success');
        });

        // 显示通知
        function showNotification(title, message, type = 'success') {
            notificationTitle.textContent = title;
            notificationMessage.textContent = message;

            // 设置图标和颜色
            if (type === 'success') {
                notificationIcon.className = 'fa fa-check-circle text-green-500 mr-3 text-xl';
            } else if (type === 'warning') {
                notificationIcon.className = 'fa fa-exclamation-triangle text-orange-500 mr-3 text-xl';
            } else if (type === 'info') {
                notificationIcon.className = 'fa fa-info-circle text-blue-500 mr-3 text-xl';
            }

            // 显示通知
            notification.classList.remove('translate-x-full');

            // 3秒后自动关闭
            setTimeout(() => {
                notification.classList.add('translate-x-full');
            }, 3000);
        }

        // 辅助函数：为颜色添加透明度
        function addOpacity(color, opacity) {
            // 处理hex颜色
            if (color.startsWith('#')) {
                // 去掉#号
                color = color.substring(1);

                // 解析RGB值
                const r = parseInt(color.substring(0, 2), 16);
                const g = parseInt(color.substring(2, 4), 16);
                const b = parseInt(color.substring(4, 6), 16);

                // 返回RGBA颜色
                return `rgba(${r}, ${g}, ${b}, ${opacity})`;
            }

            // 如果不是hex颜色，直接返回原颜色
            return color;
        }

        // 数组乱序函数
        function shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
            return array;
        }

        // 初始化
        document.addEventListener('DOMContentLoaded', function () {
            // 初始化图表类型按钮
            initChartTypeButtons();

            // 初始更新数据列表和图表
            updateDataList();
            updateChart();
        });
    </script>
</body>

</html>